﻿using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;


namespace advadev.Windows.Graph
{

    /// <summary>
    /// Represents a graph segment
    /// </summary>
    public class GraphSegment : Shape
    {

        /// <summary>for internal use</summary>
        private EventHandler _onLineDirectionChangedEventHandler;
        /// <summary>for internal use</summary>
        private EventHandler _onLineOffsetChangedEventHandler;
       
        
        /// <summary>
        /// Initializes the GraphSegment class
        /// </summary>
        static GraphSegment()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(GraphSegment), new FrameworkPropertyMetadata(typeof(GraphSegment)));
        }

        /// <summary>
        /// Initializes a new instance of the GraphSegment class
        /// </summary>
        public GraphSegment()
        {
            _onLineDirectionChangedEventHandler = new EventHandler((object sender, EventArgs args) =>
            {
                InvalidateVisual();
            });
            _onLineOffsetChangedEventHandler = new EventHandler((object sender, EventArgs args) =>
            {
                InvalidateVisual();
            });
        }


        #region dependency properties
        static public readonly DependencyProperty LineDirectionProperty = DependencyProperty.Register("LineDirection", typeof(GraphLineDirection), typeof(GraphSegment), new UIPropertyMetadata(GraphLineDirection.HorizontalToHorizontal));
        public GraphLineDirection LineDirection
        {
            get { return (GraphLineDirection)GetValue(LineDirectionProperty); }
            set { SetValue(LineDirectionProperty, value); }
        }

        static public readonly DependencyProperty LineOffsetProperty = DependencyProperty.Register("LineOffset", typeof(double?), typeof(GraphSegment), new UIPropertyMetadata(null));
        public double? LineOffset
        {
            get { return (double?)GetValue(LineOffsetProperty); }
            set { SetValue(LineOffsetProperty, value); }
        }

        static public readonly DependencyProperty FilterColorProperty = DependencyProperty.Register("FilterColor", typeof(Color), typeof(GraphSegment), new PropertyMetadata(Color.FromRgb(0xFF, 0xFF, 0xFF), onFilterColorChanged));
        public Color FilterColor
        {
            get { return (Color)GetValue(FilterColorProperty); }
            set { SetValue(FilterColorProperty, value); }
        }

        static internal readonly DependencyProperty FilterColorBrushProperty = DependencyProperty.Register("FilterColorBrush", typeof(SolidColorBrush), typeof(GraphSegment), new PropertyMetadata(new SolidColorBrush(Color.FromRgb(0xFF, 0xFF, 0xFF))));
        internal SolidColorBrush FilterColorBrush
        {
            get { return (SolidColorBrush)GetValue(FilterColorBrushProperty); }
            set { SetValue(FilterColorBrushProperty, value); }
        }
        
        static internal readonly DependencyProperty ParentGraphProperty = DependencyProperty.Register("ParentGraph", typeof(Graph), typeof(GraphSegment), new UIPropertyMetadata(null));
        internal Graph ParentGraph
        {
            get { return (Graph)GetValue(ParentGraphProperty); }
            set { SetValue(ParentGraphProperty, value); }
        }

        static internal readonly DependencyProperty StartElementProperty = DependencyProperty.Register("StartElement", typeof(UIElement), typeof(GraphSegment), new UIPropertyMetadata(null));
        internal UIElement StartElement
        {
            get { return (UIElement)GetValue(StartElementProperty); }
            set { SetValue(StartElementProperty, value); }
        }

        static internal readonly DependencyProperty EndElementProperty = DependencyProperty.Register("EndElement", typeof(UIElement), typeof(GraphSegment), new UIPropertyMetadata(null));
        internal UIElement EndElement
        {
            get { return (UIElement)GetValue(EndElementProperty); }
            set { SetValue(EndElementProperty, value); }
        }

        static internal readonly DependencyProperty StartPointProperty = DependencyProperty.Register("StartPoint", typeof(Point), typeof(GraphSegment), new UIPropertyMetadata(new Point(0d, 0d), onStartPointChanged));
        public Point StartPoint
        {
            get { return (Point)GetValue(StartPointProperty); }
            set { SetValue(StartPointProperty, value); }
        }

        static internal readonly DependencyProperty EndPointProperty = DependencyProperty.Register("EndPoint", typeof(Point), typeof(GraphSegment), new UIPropertyMetadata(new Point(0d, 0d), onEndPointChanged));
        public Point EndPoint
        {
            get { return (Point)GetValue(EndPointProperty); }
            set { SetValue(EndPointProperty, value); }
        }
        #endregion dependency properties


        /// <summary>
        /// Gets a value that represents the geometry of the shape
        /// </summary>
        override protected Geometry DefiningGeometry
        {
            get
            {
                return new RectangleGeometry(new Rect(StartPoint, EndPoint));
            }
        }

        /// <summary>
        /// Gets or sets a flag indicating whether a layer element above of the
        /// graph segment was hit during the hit test
        /// </summary>
        internal bool LayerElementHit
        {
            get;
            set;
        }


        /// <summary>
        /// Renders the element to the given drawing context
        /// </summary>
        /// <param name="drawingContext">
        /// Drawing context
        /// </param>
        override protected void OnRender(DrawingContext drawingContext)
        {
            // initialize from start- and end-elements
            GraphSegmentContainer graphSegmentContainer = TemplatedParent as GraphSegmentContainer;
            if (graphSegmentContainer != null)
            {
                Clip = graphSegmentContainer.ClipGeometry;
            }
            GraphLineDirection? direction = GraphLineDirection.HorizontalToHorizontal;
            double? offset = null;
            HorizontalAlignment horizontalStartAlignment = HorizontalAlignment.Center;
            HorizontalAlignment horizontalEndAlignment = HorizontalAlignment.Center;
            VerticalAlignment verticalStartAlignment = VerticalAlignment.Center;
            VerticalAlignment verticalEndAlignment = VerticalAlignment.Center;
            if (StartElement != null)
            {
                if (ParentGraph != null)
                {
                    Style = ParentGraph.GetGraphSegmentStyle(StartElement);
                }
                direction = GraphContainer.GetLineDirection(StartElement);
                if (direction == null)
                {
                    direction = LineDirection;
                }
                offset = GraphContainer.GetLineOffset(StartElement);
                if (offset == null)
                {
                    offset = LineOffset;
                }
                horizontalStartAlignment = GraphContainer.GetHorizontalStartNodeAlignment(StartElement);
                verticalStartAlignment = GraphContainer.GetVerticalStartNodeAlignment(StartElement);
            }
            if (EndElement != null)
            {
                horizontalEndAlignment = GraphContainer.GetHorizontalEndNodeAlignment(EndElement);
                verticalEndAlignment = GraphContainer.GetVerticalEndNodeAlignment(EndElement);
            }

            // create pens
            Matrix matrix = PresentationSource.FromVisual(this).CompositionTarget.TransformToDevice;
            EdgeMode edgeMode = (EdgeMode)GetValue(RenderOptions.EdgeModeProperty);
            double dpiFactor = (edgeMode == EdgeMode.Aliased ? 1 / matrix.M11 : 1);
            Pen pen = new Pen(Stroke, StrokeThickness);
            Pen backgroundPen = new Pen(Brushes.Transparent, StrokeThickness);
            pen.DashStyle = new DashStyle(StrokeDashArray, StrokeDashOffset);
            pen.DashCap = StrokeDashCap;
            pen.EndLineCap = StrokeEndLineCap;
            pen.LineJoin = StrokeLineJoin;
            pen.MiterLimit = StrokeMiterLimit;
            pen.StartLineCap = StrokeStartLineCap;

            // update start and end point
            Point startPoint = new Point(Math.Round(StartPoint.X, 2), Math.Round(StartPoint.Y, 2));
            Point endPoint = new Point(Math.Round(EndPoint.X, 2), Math.Round(EndPoint.Y, 2));
            double dpiStrokeWidth = Math.Round(StrokeThickness / dpiFactor, MidpointRounding.AwayFromZero) * dpiFactor;
            snapsToDevicePixels(ref startPoint);
            snapsToDevicePixels(ref endPoint);

            // move point left / up based on alignments
            if (horizontalStartAlignment == HorizontalAlignment.Center &&
                (direction == GraphLineDirection.VerticalToHorizonal || direction == GraphLineDirection.VerticalToVertical))
            {
                startPoint.X -= dpiStrokeWidth / 2d;
            }
            else if (horizontalStartAlignment == HorizontalAlignment.Right &&
                (direction == GraphLineDirection.VerticalToHorizonal || direction == GraphLineDirection.VerticalToVertical))
            {
                startPoint.X -= dpiStrokeWidth;
            }
            if (verticalStartAlignment == VerticalAlignment.Center &&
                (direction == GraphLineDirection.HorizontalToVertical || direction == GraphLineDirection.HorizontalToHorizontal))
            {
                startPoint.Y -= dpiStrokeWidth / 2d;
            }
            else if (verticalStartAlignment == VerticalAlignment.Bottom &&
                (direction == GraphLineDirection.HorizontalToVertical || direction == GraphLineDirection.HorizontalToHorizontal))
            {
                startPoint.Y -= dpiStrokeWidth;
            }
            if (horizontalEndAlignment == HorizontalAlignment.Center &&
                (direction == GraphLineDirection.HorizontalToVertical || direction == GraphLineDirection.VerticalToVertical))
            {
                endPoint.X -= dpiStrokeWidth / 2d;
            }
            else if (horizontalEndAlignment == HorizontalAlignment.Right &&
                (direction == GraphLineDirection.HorizontalToVertical || direction == GraphLineDirection.VerticalToVertical))
            {
                endPoint.X -= dpiStrokeWidth;
            }
            if (verticalEndAlignment == VerticalAlignment.Center &&
                (direction == GraphLineDirection.VerticalToHorizonal || direction == GraphLineDirection.HorizontalToHorizontal))
            {
                endPoint.Y -= dpiStrokeWidth / 2d;
            }
            else if (verticalEndAlignment == VerticalAlignment.Bottom &&
                (direction == GraphLineDirection.VerticalToHorizonal || direction == GraphLineDirection.HorizontalToHorizontal))
            {
                endPoint.Y -= dpiStrokeWidth;
            }

            // move points left / up by stroke thickness
            if (direction == GraphLineDirection.VerticalToHorizonal || direction == GraphLineDirection.VerticalToVertical)
            {
                startPoint.X += dpiStrokeWidth / 2d;
            }
            if (direction == GraphLineDirection.HorizontalToVertical || direction == GraphLineDirection.HorizontalToHorizontal)
            {
                startPoint.Y += dpiStrokeWidth / 2d;
            }
            if (direction == GraphLineDirection.HorizontalToVertical || direction == GraphLineDirection.VerticalToVertical)
            {
                endPoint.X += dpiStrokeWidth / 2d;
            }
            if (direction == GraphLineDirection.VerticalToHorizonal || direction == GraphLineDirection.HorizontalToHorizontal)
            {
                endPoint.Y += dpiStrokeWidth / 2d;
            }

            // create guideline set
            GuidelineSet guidelines = createGuidelines(horizontalStartAlignment, verticalStartAlignment, horizontalEndAlignment, verticalEndAlignment, startPoint, endPoint, pen.Thickness / 2d);
            drawingContext.PushGuidelineSet(guidelines);

            // draw lines
            Point intermediatePoint1 = new Point(0d, 0d);
            Point intermediatePoint2 = new Point(0d, 0d);
            double offsetX = (offset != null && Math.Abs(offset.Value) <= Math.Abs(endPoint.X - startPoint.X) ? offset.Value : Math.Abs(endPoint.X - startPoint.X) / 2d);
            double offsetY = (offset != null && Math.Abs(offset.Value) <= Math.Abs(endPoint.Y - startPoint.Y) ? offset.Value : Math.Abs(endPoint.Y - startPoint.Y) / 2d);
            switch (direction.Value)
            {
                case GraphLineDirection.Direct:
                    drawingContext.DrawLine(backgroundPen, startPoint, endPoint);
                    drawingContext.DrawLine(pen, startPoint, endPoint);
                    break;
                case GraphLineDirection.HorizontalToHorizontal:
                    intermediatePoint1.X = startPoint.X + (offsetX * (endPoint.X >= startPoint.X ? 1 : -1));
                    intermediatePoint1.Y = startPoint.Y;
                    intermediatePoint2.X = intermediatePoint1.X;
                    intermediatePoint2.Y = endPoint.Y;
                    if (edgeMode == EdgeMode.Aliased)
                    {
                        snapsToDevicePixels(ref intermediatePoint1);
                        intermediatePoint1.Y = startPoint.Y;
                        intermediatePoint2.X = intermediatePoint1.X;
                    }
                    drawingContext.DrawLine(backgroundPen, startPoint, intermediatePoint1);
                    drawingContext.DrawLine(backgroundPen, intermediatePoint1, intermediatePoint2);
                    drawingContext.DrawLine(backgroundPen, intermediatePoint2, endPoint);
                    drawingContext.DrawLine(pen, startPoint, intermediatePoint1);
                    drawingContext.DrawLine(pen, intermediatePoint1, intermediatePoint2);
                    drawingContext.DrawLine(pen, intermediatePoint2, endPoint);
                    break;
                case GraphLineDirection.HorizontalToVertical:
                    intermediatePoint1.X = endPoint.X;
                    intermediatePoint1.Y = startPoint.Y;
                    drawingContext.DrawLine(backgroundPen, startPoint, intermediatePoint1);
                    drawingContext.DrawLine(backgroundPen, intermediatePoint1, endPoint);
                    drawingContext.DrawLine(pen, startPoint, intermediatePoint1);
                    drawingContext.DrawLine(pen, intermediatePoint1, endPoint);
                    break;
                case GraphLineDirection.VerticalToHorizonal:
                    intermediatePoint1.X = startPoint.X;
                    intermediatePoint1.Y = endPoint.Y;
                    drawingContext.DrawLine(backgroundPen, startPoint, intermediatePoint1);
                    drawingContext.DrawLine(backgroundPen, intermediatePoint1, endPoint);
                    drawingContext.DrawLine(pen, startPoint, intermediatePoint1);
                    drawingContext.DrawLine(pen, intermediatePoint1, endPoint);
                    break;
                case GraphLineDirection.VerticalToVertical:
                    intermediatePoint1.X = startPoint.X;
                    intermediatePoint1.Y = startPoint.Y + (offsetY * (endPoint.Y >= startPoint.Y ? 1 : -1));
                    intermediatePoint2.X = endPoint.X;
                    intermediatePoint2.Y = intermediatePoint1.Y;
                    if (edgeMode == EdgeMode.Aliased)
                    {
                        snapsToDevicePixels(ref intermediatePoint1);
                        intermediatePoint1.X = startPoint.X;
                        intermediatePoint2.Y = intermediatePoint1.Y;
                    }
                    drawingContext.DrawLine(backgroundPen, startPoint, intermediatePoint1);
                    drawingContext.DrawLine(backgroundPen, intermediatePoint1, intermediatePoint2);
                    drawingContext.DrawLine(backgroundPen, intermediatePoint2, endPoint);
                    drawingContext.DrawLine(pen, startPoint, intermediatePoint1);
                    drawingContext.DrawLine(pen, intermediatePoint1, intermediatePoint2);
                    drawingContext.DrawLine(pen, intermediatePoint2, endPoint);
                    break;
                default:
                    drawingContext.DrawLine(backgroundPen, startPoint, endPoint);
                    drawingContext.DrawLine(pen, startPoint, endPoint);
                    break;
            }
            drawingContext.Pop();
        }

        /// <summary>
        /// Executes the hit test
        /// </summary>
        /// <param name="hitTestParameters">
        /// Hit test parameters
        /// </param>
        /// <returns>
        /// Hit test result
        /// </returns>
        override protected HitTestResult HitTestCore(PointHitTestParameters hitTestParameters)
        {
            if (!LayerElementHit)
            {
                return base.HitTestCore(hitTestParameters);
            }
            LayerElementHit = false;
            return null;
        }

        /// <summary>
        /// Handles the "Changed" event of the "FilterColor" dependency property
        /// </summary>
        /// <param name="sender">
        /// Sender of the event
        /// </param>
        /// <param name="args">
        /// Event argument
        /// </param>
        static private void onFilterColorChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            GraphSegment graphSegment = sender as GraphSegment;
            if (graphSegment != null)
            {
                graphSegment.FilterColorBrush = new SolidColorBrush(graphSegment.FilterColor);
            }
        }

        /// <summary>
        /// Handles the "Changed" event of the "StartElement" dependency
        /// property
        /// </summary>
        /// <param name="sender">
        /// Sender of the event
        /// </param>
        /// <param name="args">
        /// Event argument
        /// </param>
        static private void onStartElementChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            GraphSegment graphSegment = sender as GraphSegment;
            if (graphSegment != null && args != null)
            {
                UIElement oldElement = args.OldValue as UIElement;
                if (oldElement != null)
                {
                    graphSegment.unregisterLineDirectionAndOffsetChangedHandler(oldElement);
                }
                UIElement newElement = args.NewValue as UIElement;
                if (newElement != null)
                {
                    graphSegment.registerLineDirectionAndOffsetChangedHandler(newElement);
                }
            }
        }

        /// <summary>
        /// Handles the "Changed" event of the "StartPoint" dependency
        /// property
        /// </summary>
        /// <param name="sender">
        /// Sender of the event
        /// </param>
        /// <param name="args">
        /// Event argument
        /// </param>
        static private void onStartPointChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            GraphSegment graphSegment = sender as GraphSegment;
            if (graphSegment != null)
            {
                graphSegment.InvalidateVisual();
            }
        }

        /// <summary>
        /// Handles the "Changed" event of the "EndPoint" dependency
        /// property
        /// </summary>
        /// <param name="sender">
        /// Sender of the event
        /// </param>
        /// <param name="args">
        /// Event argument
        /// </param>
        static private void onEndPointChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            GraphSegment graphSegment = sender as GraphSegment;
            if (graphSegment != null)
            {
                graphSegment.InvalidateVisual();
            }
        }

        /// <summary>
        /// Registers the line direction and offset changed handler for the
        /// given node element
        /// </summary>
        /// <param name="nodeElement">
        /// Node element
        /// </param>
        private void registerLineDirectionAndOffsetChangedHandler(UIElement nodeElement)
        {
            DependencyPropertyDescriptor lineDirectionDescriptor = DependencyPropertyDescriptor.FromProperty(GraphContainer.LineDirectionProperty, typeof(GraphSegment));
            if (lineDirectionDescriptor != null)
            {
                lineDirectionDescriptor.AddValueChanged(nodeElement, _onLineDirectionChangedEventHandler);
            }
            DependencyPropertyDescriptor lineOffsetDescriptor = DependencyPropertyDescriptor.FromProperty(GraphContainer.LineOffsetProperty, typeof(GraphSegment));
            if (lineOffsetDescriptor != null)
            {
                lineOffsetDescriptor.AddValueChanged(nodeElement, _onLineOffsetChangedEventHandler);
            }
        }

        /// <summary>
        /// Unregisters the line direction and offset changed handler for the
        /// given node element
        /// </summary>
        /// <param name="nodeElement">
        /// Node element
        /// </param>
        private void unregisterLineDirectionAndOffsetChangedHandler(UIElement nodeElement)
        {
            DependencyPropertyDescriptor lineDirectionDescriptor = DependencyPropertyDescriptor.FromProperty(GraphContainer.LineDirectionProperty, typeof(GraphSegment));
            if (lineDirectionDescriptor != null)
            {
                lineDirectionDescriptor.RemoveValueChanged(nodeElement, _onLineDirectionChangedEventHandler);
            }
            DependencyPropertyDescriptor lineOffsetDescriptor = DependencyPropertyDescriptor.FromProperty(GraphContainer.LineOffsetProperty, typeof(GraphSegment));
            if (lineOffsetDescriptor != null)
            {
                lineOffsetDescriptor.RemoveValueChanged(nodeElement, _onLineOffsetChangedEventHandler);
            }
        }

        /// <summary>
        /// Snaps the given point to the device pixels (if necessary)
        /// </summary>
        /// <param name="point">
        /// Point
        /// </param>
        private void snapsToDevicePixels(ref Point point)
        {
            if (SnapsToDevicePixels)
            {
                Matrix matrix = PresentationSource.FromVisual(this).CompositionTarget.TransformToDevice;
                double dpiFactor = 1 / matrix.M11;
                point.X = Math.Round(Math.Round(point.X / dpiFactor, MidpointRounding.AwayFromZero) * dpiFactor, 2);
                point.Y = Math.Round(Math.Round(point.Y / dpiFactor, MidpointRounding.AwayFromZero) * dpiFactor, 2);
            }
        }

        /// <summary>
        /// Create guidelines
        /// </summary>
        /// <param name="horizontalStartAlignment">
        /// Horizontal start alignment
        /// </param>
        /// <param name="verticalStartAlignment">
        /// Vertical start alignment
        /// </param>
        /// <param name="horizontalEndAlignment">
        /// Horizontal end alignment
        /// </param>
        /// <param name="verticalEndAlignment">
        /// Vertical end alignment
        /// </param>
        /// <param name="startPoint">
        /// Start point
        /// </param>
        /// <param name="endPoint">
        /// End point
        /// </param>
        /// <param name="halfPenWidth">
        /// Half pen width
        /// </param>
        /// <returns>
        /// Guidelines
        /// </returns>
        private GuidelineSet createGuidelines(HorizontalAlignment horizontalStartAlignment, VerticalAlignment verticalStartAlignment, HorizontalAlignment horizontalEndAlignment, VerticalAlignment verticalEndAlignment, Point startPoint, Point endPoint, double halfPenWidth)
        {
            GuidelineSet guidelines = new GuidelineSet();
            Rect rect = new Rect(startPoint, endPoint);
            EdgeMode edgeMode = (EdgeMode)GetValue(RenderOptions.EdgeModeProperty);
            if (edgeMode == EdgeMode.Aliased)
            {
                guidelines.GuidelinesX.Add(rect.Left + halfPenWidth);
                guidelines.GuidelinesX.Add(rect.Right + halfPenWidth);
                guidelines.GuidelinesY.Add(rect.Top + halfPenWidth);
                guidelines.GuidelinesY.Add(rect.Bottom + halfPenWidth);
                return guidelines;
            }
            if (horizontalStartAlignment == HorizontalAlignment.Left && horizontalEndAlignment == HorizontalAlignment.Left)
            {
                guidelines.GuidelinesX.Add(rect.Left - halfPenWidth);
                guidelines.GuidelinesX.Add(rect.Right - halfPenWidth);
            }
            else if (horizontalStartAlignment == HorizontalAlignment.Left && horizontalEndAlignment == HorizontalAlignment.Center)
            {
                if (startPoint.Y < endPoint.Y)
                {
                    guidelines.GuidelinesX.Add(rect.Left - halfPenWidth);
                    guidelines.GuidelinesX.Add(rect.Right);
                }
                else if (startPoint.Y > endPoint.Y)
                {
                    guidelines.GuidelinesX.Add(rect.Left);
                    guidelines.GuidelinesX.Add(rect.Right - halfPenWidth);
                }
                else
                {
                    guidelines.GuidelinesX.Add(rect.Left);
                    guidelines.GuidelinesX.Add(rect.Right);
                }
            }
            else if (horizontalStartAlignment == HorizontalAlignment.Left && horizontalEndAlignment == HorizontalAlignment.Right)
            {
                if (startPoint.Y < endPoint.Y)
                {
                    guidelines.GuidelinesX.Add(rect.Left - halfPenWidth);
                    guidelines.GuidelinesX.Add(rect.Right + halfPenWidth);
                }
                else if (startPoint.Y > endPoint.Y)
                {
                    guidelines.GuidelinesX.Add(rect.Left + halfPenWidth);
                    guidelines.GuidelinesX.Add(rect.Right - halfPenWidth);
                }
                else
                {
                    guidelines.GuidelinesX.Add(rect.Left);
                    guidelines.GuidelinesX.Add(rect.Right);
                }
            }
            else if (horizontalStartAlignment == HorizontalAlignment.Center && horizontalEndAlignment == HorizontalAlignment.Left)
            {
                if (startPoint.Y < endPoint.Y)
                {
                    guidelines.GuidelinesX.Add(rect.Left);
                    guidelines.GuidelinesX.Add(rect.Right - halfPenWidth);
                }
                else if (startPoint.Y > endPoint.Y)
                {
                    guidelines.GuidelinesX.Add(rect.Left - halfPenWidth);
                    guidelines.GuidelinesX.Add(rect.Right);
                }
                else
                {
                    guidelines.GuidelinesX.Add(rect.Left);
                    guidelines.GuidelinesX.Add(rect.Right);
                }
            }
            else if (horizontalStartAlignment == HorizontalAlignment.Center && horizontalEndAlignment == HorizontalAlignment.Right)
            {
                if (startPoint.Y < endPoint.Y)
                {
                    guidelines.GuidelinesX.Add(rect.Left);
                    guidelines.GuidelinesX.Add(rect.Right + halfPenWidth);
                }
                else if (startPoint.Y > endPoint.Y)
                {
                    guidelines.GuidelinesX.Add(rect.Left + halfPenWidth);
                    guidelines.GuidelinesX.Add(rect.Right);
                }
                else
                {
                    guidelines.GuidelinesX.Add(rect.Left);
                    guidelines.GuidelinesX.Add(rect.Right);
                }
            }
            else if (horizontalStartAlignment == HorizontalAlignment.Right && horizontalEndAlignment == HorizontalAlignment.Left)
            {
                if (startPoint.Y < endPoint.Y)
                {
                    guidelines.GuidelinesX.Add(rect.Left + halfPenWidth);
                    guidelines.GuidelinesX.Add(rect.Right - halfPenWidth);
                }
                else if (startPoint.Y > endPoint.Y)
                {
                    guidelines.GuidelinesX.Add(rect.Left - halfPenWidth);
                    guidelines.GuidelinesX.Add(rect.Right + halfPenWidth);
                }
                else
                {
                    guidelines.GuidelinesX.Add(rect.Left);
                    guidelines.GuidelinesX.Add(rect.Right);
                }
            }
            else if (horizontalStartAlignment == HorizontalAlignment.Right && horizontalEndAlignment == HorizontalAlignment.Center)
            {
                if (startPoint.Y < endPoint.Y)
                {
                    guidelines.GuidelinesX.Add(rect.Left + halfPenWidth);
                    guidelines.GuidelinesX.Add(rect.Right);
                }
                else if (startPoint.Y > endPoint.Y)
                {
                    guidelines.GuidelinesX.Add(rect.Left);
                    guidelines.GuidelinesX.Add(rect.Right + halfPenWidth);
                }
                else
                {
                    guidelines.GuidelinesX.Add(rect.Left);
                    guidelines.GuidelinesX.Add(rect.Right);
                }
            }
            else if (horizontalStartAlignment == HorizontalAlignment.Right && horizontalEndAlignment == HorizontalAlignment.Right)
            {
                guidelines.GuidelinesX.Add(rect.Left + halfPenWidth);
                guidelines.GuidelinesX.Add(rect.Right + halfPenWidth);
            }
            else
            {
                guidelines.GuidelinesX.Add(rect.Left);
                guidelines.GuidelinesX.Add(rect.Right);
            }

            if (verticalStartAlignment == VerticalAlignment.Top && verticalEndAlignment == VerticalAlignment.Top)
            {
                guidelines.GuidelinesY.Add(rect.Top - halfPenWidth);
                guidelines.GuidelinesY.Add(rect.Bottom - halfPenWidth);
            }
            else if (verticalStartAlignment == VerticalAlignment.Top && verticalEndAlignment == VerticalAlignment.Center)
            {
                if (startPoint.Y < endPoint.Y)
                {
                    guidelines.GuidelinesY.Add(rect.Top - halfPenWidth);
                    guidelines.GuidelinesY.Add(rect.Bottom);
                }
                else if (startPoint.Y > endPoint.Y)
                {
                    guidelines.GuidelinesY.Add(rect.Top);
                    guidelines.GuidelinesY.Add(rect.Bottom - halfPenWidth);
                }
                else
                {
                    guidelines.GuidelinesY.Add(rect.Top);
                    guidelines.GuidelinesY.Add(rect.Bottom);
                }
            }
            else if (verticalStartAlignment == VerticalAlignment.Top && verticalEndAlignment == VerticalAlignment.Bottom)
            {
                if (startPoint.Y < endPoint.Y)
                {
                    guidelines.GuidelinesY.Add(rect.Top - halfPenWidth);
                    guidelines.GuidelinesY.Add(rect.Bottom + halfPenWidth);
                }
                else if (startPoint.Y > endPoint.Y)
                {
                    guidelines.GuidelinesY.Add(rect.Top + halfPenWidth);
                    guidelines.GuidelinesY.Add(rect.Bottom - halfPenWidth);
                }
                else
                {
                    guidelines.GuidelinesY.Add(rect.Top);
                    guidelines.GuidelinesY.Add(rect.Bottom);
                }
            }
            else if (verticalStartAlignment == VerticalAlignment.Center && verticalEndAlignment == VerticalAlignment.Top)
            {
                if (startPoint.Y < endPoint.Y)
                {
                    guidelines.GuidelinesY.Add(rect.Top);
                    guidelines.GuidelinesY.Add(rect.Bottom - halfPenWidth);
                }
                else if (startPoint.Y > endPoint.Y)
                {
                    guidelines.GuidelinesY.Add(rect.Top - halfPenWidth);
                    guidelines.GuidelinesY.Add(rect.Bottom);
                }
                else
                {
                    guidelines.GuidelinesY.Add(rect.Top);
                    guidelines.GuidelinesY.Add(rect.Bottom);
                }
            }
            else if (verticalStartAlignment == VerticalAlignment.Center && verticalEndAlignment == VerticalAlignment.Bottom)
            {
                if (startPoint.Y < endPoint.Y)
                {
                    guidelines.GuidelinesY.Add(rect.Top);
                    guidelines.GuidelinesY.Add(rect.Bottom + halfPenWidth);
                }
                else if (startPoint.Y > endPoint.Y)
                {
                    guidelines.GuidelinesY.Add(rect.Top + halfPenWidth);
                    guidelines.GuidelinesY.Add(rect.Bottom);
                }
                else
                {
                    guidelines.GuidelinesY.Add(rect.Top);
                    guidelines.GuidelinesY.Add(rect.Bottom);
                }
            }
            else if (verticalStartAlignment == VerticalAlignment.Bottom && verticalEndAlignment == VerticalAlignment.Top)
            {
                if (startPoint.Y < endPoint.Y)
                {
                    guidelines.GuidelinesY.Add(rect.Top + halfPenWidth);
                    guidelines.GuidelinesY.Add(rect.Bottom - halfPenWidth);
                }
                else if (startPoint.Y > endPoint.Y)
                {
                    guidelines.GuidelinesY.Add(rect.Top - halfPenWidth);
                    guidelines.GuidelinesY.Add(rect.Bottom + halfPenWidth);
                }
                else
                {
                    guidelines.GuidelinesY.Add(rect.Top);
                    guidelines.GuidelinesY.Add(rect.Bottom);
                }
            }
            else if (verticalStartAlignment == VerticalAlignment.Bottom && verticalEndAlignment == VerticalAlignment.Center)
            {
                if (startPoint.Y < endPoint.Y)
                {
                    guidelines.GuidelinesY.Add(rect.Top + halfPenWidth);
                    guidelines.GuidelinesY.Add(rect.Bottom);
                }
                else if (startPoint.Y > endPoint.Y)
                {
                    guidelines.GuidelinesY.Add(rect.Top);
                    guidelines.GuidelinesY.Add(rect.Bottom + halfPenWidth);
                }
                else
                {
                    guidelines.GuidelinesY.Add(rect.Top);
                    guidelines.GuidelinesY.Add(rect.Bottom);
                }
            }
            else if (verticalStartAlignment == VerticalAlignment.Bottom && verticalEndAlignment == VerticalAlignment.Bottom)
            {
                guidelines.GuidelinesY.Add(rect.Top + halfPenWidth);
                guidelines.GuidelinesY.Add(rect.Bottom + halfPenWidth);
            }
            else
            {
                guidelines.GuidelinesY.Add(rect.Top);
                guidelines.GuidelinesY.Add(rect.Bottom);
            }
            return guidelines;
        }

    }

}
